//! # 认证配置
//!
//! 定义认证相关的配置结构和选项。

use serde::{Deserialize, Serialize};
use std::time::Duration;

/// 认证配置
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AuthConfig {
    /// 认证超时时间（秒）
    pub timeout_seconds: u64,
    /// 是否启用多因素认证
    pub mfa_enabled: bool,
    /// 允许的失败尝试次数
    pub max_failed_attempts: u32,
    /// 账户锁定时间（秒）
    pub lockout_duration_seconds: u64,
    /// 是否启用会话
    pub session_enabled: bool,
    /// 会话配置
    pub session_config: SessionConfig,
    /// 令牌配置
    pub token_config: TokenConfig,
    /// 权限配置
    pub permission_config: PermissionConfig,
}

/// 会话配置
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SessionConfig {
    /// 会话超时时间（秒）
    pub timeout_seconds: u64,
    /// 最大并发会话数
    pub max_concurrent_sessions: u32,
    /// 是否启用会话续期
    pub enable_renewal: bool,
    /// 会话续期阈值（剩余时间少于此值时自动续期）
    pub renewal_threshold_seconds: u64,
    /// 会话存储类型
    pub storage_type: SessionStorageType,
    /// 会话存储配置
    pub storage_config: serde_json::Value,
}

/// 会话存储类型
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum SessionStorageType {
    /// 内存存储
    Memory,
    /// Redis存储
    Redis,
    /// 数据库存储
    Database,
}

/// 令牌配置
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TokenConfig {
    /// 访问令牌有效期（秒）
    pub access_token_ttl: u64,
    /// 刷新令牌有效期（秒）
    pub refresh_token_ttl: u64,
    /// 令牌长度（字节）
    pub token_length: u32,
    /// 是否启用令牌刷新
    pub refresh_enabled: bool,
    /// 刷新令牌轮换
    pub refresh_rotation: bool,
    /// 令牌黑名单配置
    pub blacklist_config: TokenBlacklistConfig,
}

/// 令牌黑名单配置
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TokenBlacklistConfig {
    /// 是否启用令牌黑名单
    pub enabled: bool,
    /// 黑名单存储类型
    pub storage_type: BlacklistStorageType,
    /// 黑名单清理间隔（秒）
    pub cleanup_interval_seconds: u64,
    /// 存储配置
    pub storage_config: serde_json::Value,
}

/// 黑名单存储类型
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum BlacklistStorageType {
    /// 内存存储
    Memory,
    /// Redis存储
    Redis,
    /// 数据库存储
    Database,
}

/// 权限配置
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PermissionConfig {
    /// 是否启用权限检查
    pub enabled: bool,
    /// 默认拒绝策略
    pub default_deny: bool,
    /// 权限缓存配置
    pub cache_config: PermissionCacheConfig,
    /// 角色继承配置
    pub role_inheritance: RoleInheritanceConfig,
    /// 权限策略配置
    pub policy_config: PolicyConfig,
}

/// 权限缓存配置
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PermissionCacheConfig {
    /// 是否启用权限缓存
    pub enabled: bool,
    /// 缓存TTL（秒）
    pub ttl_seconds: u64,
    /// 最大缓存条目数
    pub max_entries: u64,
    /// 缓存刷新策略
    pub refresh_strategy: CacheRefreshStrategy,
}

/// 缓存刷新策略
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum CacheRefreshStrategy {
    /// 惰性刷新（访问时检查是否过期）
    Lazy,
    /// 主动刷新（定时刷新）
    Active,
    /// 混合刷新
    Hybrid,
}

/// 角色继承配置
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RoleInheritanceConfig {
    /// 是否启用角色继承
    pub enabled: bool,
    /// 最大继承深度
    pub max_depth: u32,
    /// 是否允许循环继承
    pub allow_cycles: bool,
}

/// 权限策略配置
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PolicyConfig {
    /// 策略评估引擎类型
    pub engine_type: PolicyEngineType,
    /// 策略文件路径
    pub policy_files: Vec<String>,
    /// 是否启用策略热重载
    pub hot_reload: bool,
    /// 策略缓存配置
    pub cache_enabled: bool,
}

/// 策略引擎类型
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum PolicyEngineType {
    /// 简单的基于规则的引擎
    Simple,
    /// RBAC引擎
    Rbac,
    /// ABAC引擎
    Abac,
    /// OPA（Open Policy Agent）
    Opa,
}

impl Default for AuthConfig {
    fn default() -> Self {
        Self {
            timeout_seconds: 30,
            mfa_enabled: false,
            max_failed_attempts: 5,
            lockout_duration_seconds: 300, // 5分钟
            session_enabled: true,
            session_config: SessionConfig::default(),
            token_config: TokenConfig::default(),
            permission_config: PermissionConfig::default(),
        }
    }
}

impl Default for SessionConfig {
    fn default() -> Self {
        Self {
            timeout_seconds: 3600, // 1小时
            max_concurrent_sessions: 10,
            enable_renewal: true,
            renewal_threshold_seconds: 600, // 10分钟
            storage_type: SessionStorageType::Memory,
            storage_config: serde_json::json!({}),
        }
    }
}

impl Default for TokenConfig {
    fn default() -> Self {
        Self {
            access_token_ttl: 3600,   // 1小时
            refresh_token_ttl: 86400, // 24小时
            token_length: 32,
            refresh_enabled: true,
            refresh_rotation: true,
            blacklist_config: TokenBlacklistConfig::default(),
        }
    }
}

impl Default for TokenBlacklistConfig {
    fn default() -> Self {
        Self {
            enabled: true,
            storage_type: BlacklistStorageType::Memory,
            cleanup_interval_seconds: 3600, // 1小时
            storage_config: serde_json::json!({}),
        }
    }
}

impl Default for PermissionConfig {
    fn default() -> Self {
        Self {
            enabled: true,
            default_deny: true,
            cache_config: PermissionCacheConfig::default(),
            role_inheritance: RoleInheritanceConfig::default(),
            policy_config: PolicyConfig::default(),
        }
    }
}

impl Default for PermissionCacheConfig {
    fn default() -> Self {
        Self {
            enabled: true,
            ttl_seconds: 300, // 5分钟
            max_entries: 10000,
            refresh_strategy: CacheRefreshStrategy::Lazy,
        }
    }
}

impl Default for RoleInheritanceConfig {
    fn default() -> Self {
        Self {
            enabled: true,
            max_depth: 10,
            allow_cycles: false,
        }
    }
}

impl Default for PolicyConfig {
    fn default() -> Self {
        Self {
            engine_type: PolicyEngineType::Rbac,
            policy_files: vec![],
            hot_reload: false,
            cache_enabled: true,
        }
    }
}

impl AuthConfig {
    /// 验证配置的有效性
    pub fn validate(&self) -> Result<(), Vec<String>> {
        let mut errors = Vec::new();

        if self.timeout_seconds == 0 {
            errors.push("Timeout seconds must be greater than 0".to_string());
        }

        if self.max_failed_attempts == 0 {
            errors.push("Max failed attempts must be greater than 0".to_string());
        }

        if self.lockout_duration_seconds == 0 {
            errors.push("Lockout duration must be greater than 0".to_string());
        }

        // 验证会话配置
        if let Err(mut session_errors) = self.session_config.validate() {
            errors.append(&mut session_errors);
        }

        // 验证令牌配置
        if let Err(mut token_errors) = self.token_config.validate() {
            errors.append(&mut token_errors);
        }

        if errors.is_empty() {
            Ok(())
        } else {
            Err(errors)
        }
    }

    /// 获取认证超时时间
    pub fn timeout(&self) -> Duration {
        Duration::from_secs(self.timeout_seconds)
    }

    /// 获取锁定持续时间
    pub fn lockout_duration(&self) -> Duration {
        Duration::from_secs(self.lockout_duration_seconds)
    }
}

impl SessionConfig {
    /// 验证会话配置
    pub fn validate(&self) -> Result<(), Vec<String>> {
        let mut errors = Vec::new();

        if self.timeout_seconds == 0 {
            errors.push("Session timeout must be greater than 0".to_string());
        }

        if self.max_concurrent_sessions == 0 {
            errors.push("Max concurrent sessions must be greater than 0".to_string());
        }

        if self.enable_renewal && self.renewal_threshold_seconds >= self.timeout_seconds {
            errors.push("Renewal threshold must be less than session timeout".to_string());
        }

        if errors.is_empty() {
            Ok(())
        } else {
            Err(errors)
        }
    }

    /// 获取会话超时时间
    pub fn timeout(&self) -> Duration {
        Duration::from_secs(self.timeout_seconds)
    }

    /// 获取续期阈值
    pub fn renewal_threshold(&self) -> Duration {
        Duration::from_secs(self.renewal_threshold_seconds)
    }
}

impl TokenConfig {
    /// 验证令牌配置
    pub fn validate(&self) -> Result<(), Vec<String>> {
        let mut errors = Vec::new();

        if self.access_token_ttl == 0 {
            errors.push("Access token TTL must be greater than 0".to_string());
        }

        if self.refresh_enabled && self.refresh_token_ttl == 0 {
            errors.push("Refresh token TTL must be greater than 0 when refresh is enabled".to_string());
        }

        if self.refresh_enabled && self.refresh_token_ttl <= self.access_token_ttl {
            errors.push("Refresh token TTL should be greater than access token TTL".to_string());
        }

        if self.token_length < 16 {
            errors.push("Token length should be at least 16 bytes for security".to_string());
        }

        if errors.is_empty() {
            Ok(())
        } else {
            Err(errors)
        }
    }

    /// 获取访问令牌TTL
    pub fn access_token_ttl(&self) -> Duration {
        Duration::from_secs(self.access_token_ttl)
    }

    /// 获取刷新令牌TTL
    pub fn refresh_token_ttl(&self) -> Duration {
        Duration::from_secs(self.refresh_token_ttl)
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_auth_config_default() {
        let config = AuthConfig::default();
        assert_eq!(config.timeout_seconds, 30);
        assert!(!config.mfa_enabled);
        assert_eq!(config.max_failed_attempts, 5);
        assert!(config.session_enabled);
    }

    #[test]
    fn test_auth_config_validation_success() {
        let config = AuthConfig::default();
        assert!(config.validate().is_ok());
    }

    #[test]
    fn test_auth_config_validation_failure() {
        let mut config = AuthConfig::default();
        config.timeout_seconds = 0;
        config.max_failed_attempts = 0;

        let result = config.validate();
        assert!(result.is_err());

        let errors = result.unwrap_err();
        assert!(errors.iter().any(|e| e.contains("Timeout seconds must be greater than 0")));
        assert!(errors.iter().any(|e| e.contains("Max failed attempts must be greater than 0")));
    }

    #[test]
    fn test_session_config_validation() {
        let mut config = SessionConfig::default();
        config.timeout_seconds = 100;
        config.renewal_threshold_seconds = 200; // 大于timeout

        let result = config.validate();
        assert!(result.is_err());
        
        let errors = result.unwrap_err();
        assert!(errors.iter().any(|e| e.contains("Renewal threshold must be less than session timeout")));
    }

    #[test]
    fn test_token_config_validation() {
        let mut config = TokenConfig::default();
        config.access_token_ttl = 3600;
        config.refresh_token_ttl = 1800; // 小于access token TTL

        let result = config.validate();
        assert!(result.is_err());
        
        let errors = result.unwrap_err();
        assert!(errors.iter().any(|e| e.contains("Refresh token TTL should be greater than access token TTL")));
    }

    #[test]
    fn test_duration_conversion() {
        let config = AuthConfig::default();
        assert_eq!(config.timeout(), Duration::from_secs(30));
        assert_eq!(config.lockout_duration(), Duration::from_secs(300));

        let session_config = SessionConfig::default();
        assert_eq!(session_config.timeout(), Duration::from_secs(3600));
        assert_eq!(session_config.renewal_threshold(), Duration::from_secs(600));

        let token_config = TokenConfig::default();
        assert_eq!(token_config.access_token_ttl(), Duration::from_secs(3600));
        assert_eq!(token_config.refresh_token_ttl(), Duration::from_secs(86400));
    }

    #[test]
    fn test_enum_serialization() {
        let storage_type = SessionStorageType::Redis;
        let json = serde_json::to_string(&storage_type).unwrap();
        assert_eq!(json, "\"redis\"");

        let policy_engine = PolicyEngineType::Opa;
        let json = serde_json::to_string(&policy_engine).unwrap();
        assert_eq!(json, "\"opa\"");
    }
}